package org.snia.server.ejb.container;

import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;

import org.snia.cdmi.ErrorCodes;
import org.snia.cdmi.auth.Principal;
import org.snia.cdmi.exception.ForbiddenException;
import org.snia.cdmi.exception.NotFoundException;
import org.snia.cdmi.model.AccessControlList;
import org.snia.cdmi.model.BaseContainer;
import org.snia.cdmi.model.Container;
import org.snia.cdmi.model.ContainerProperties;
import org.snia.cdmi.model.ContainerStatus;
import org.snia.cdmi.model.MetaContainer;
import org.snia.exception.BusinessException;
import org.snia.server.ejb.cache.CacheBean;
import org.snia.server.ejb.cache.CacheOperation;
import org.snia.server.model.cache.ContainerCache;
import org.snia.server.processor.MetaContainerXMLProcessor;
import org.snia.server.processor.MetaProcessor;
import org.snia.util.JuuidUtils;

@Stateless
@Local(ContainerOperation.class)
@Remote(RemoteContainerOperation.class)
public class ContainerBean implements ContainerOperation {

	// @EJB(beanName="CacheBean") LocalCacheOperation cache_local;
	CacheOperation cache_local = new CacheBean();

	@Override
	public void createContainer(Container container, Principal principal){
		BaseContainer cache = null;
		cache = (ContainerCache) cache_local.getCache(container.getName());
		if (cache == null) {			
			if (this.exist(container.getName())) {
				// 容器已经存在，抛出异常
				throw new BusinessException(ErrorCodes.ContainerAlreadyExists);
			}
			// 创建新容器的元数据信息
			this.createMetaContainer(container);
			// 将创建的新容器放入到缓存中
			cache = new ContainerCache();
			cache.setName(container.getName());
			cache.setAccessKey(container.getAccessKey());
			String uuid  = JuuidUtils.getuuid(container.getName());
			cache_local.putCache(uuid, cache, 0);
		} else {
			throw new BusinessException(ErrorCodes.ContainerAlreadyExists);
		}
	}


	/**
	 * 在本地节点中检查容器元数据是否存在
	 * 
	 * @param containerName
	 *            容器名
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	@Override
	public boolean exist(String container) {
		MetaProcessor processor = new MetaContainerXMLProcessor();
		return processor.exist(container);
	}

	/**
	 * 向本地节点写入元数据文件
	 * 
	 * @param container
	 */
	@Override
	public void createMetaContainer(Container container) {
		try {
			// 装配容器的元数据文件对象
			MetaContainer meta = new MetaContainer();
			// 设置元数据文件的文件UUID
			meta.setName(container.getName());
			meta.setCreationDate(container.getCreationDate());
			meta.setAccessKey(container.getAccessKey());
			// meta.setSites(container.getSites());
			meta.setPermission(container.getPermission());
			meta.setStatus(ContainerStatus.Working.getValue());
			meta.setMetadata(container.getUserMetadata());
			meta.setAccessControlPolicy(container.getAccessControlList());
			// 将容器的元数据文件对象序列化为文件
			MetaProcessor processor = new MetaContainerXMLProcessor();
			String uuid  = JuuidUtils.getuuid(container.getName());
			processor.createMetadata(uuid, meta);
//			toXMLFile(meta);

		} catch (BusinessException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 向本地节点获得元数据文件
	 * 
	 * @param container
	 * @throws NoSuchAlgorithmException
	 */
	@Override
	public MetaContainer getMetaContainer(String uuid) {

		MetaProcessor processor = new MetaContainerXMLProcessor();
		Object meta = processor.getMetadata(uuid);
		return (meta == null) ? null : (MetaContainer)meta;
	}

	@Override
	public void deleteContainer(String name, Principal principal) {

		ContainerCache cache = null;
		cache = (ContainerCache) cache_local.getCache(name);
		MetaContainer metafile = this.getMetaContainer(name);
		if (cache != null) {
			if (cache.getStatus() != ContainerStatus.Working.getValue()) {
				// 只有容器状态为正常时，才能进行容器的删除，否则返回409.冲突
				throw new ForbiddenException(ErrorCodes.OperationAborted);
			}
		}
		// 从元数据文件，获得容器状态，进行比较
		if (metafile != null) {
			if (metafile.getStatus() != ContainerStatus.Working.getValue()) {
				// 只有容器状态为正常时，才能进行容器的删除，否则返回409.冲突
				throw new ForbiddenException(ErrorCodes.OperationAborted);
			}
		} else {
			// 元数据文件不存在
			throw new NotFoundException(ErrorCodes.NoSuchContainer);
		}

		// 更新容器元数据文件中的容器状态
		metafile.setStatus(ContainerStatus.Releasing.getValue());
		String uuid  = JuuidUtils.getuuid(metafile.getName());
		this.updateMetaContainer(uuid, metafile);


		// 如果存在缓存，则更新缓存状态。
		if (cache != null) {
			cache.setStatus(ContainerStatus.Releasing.getValue());
			cache_local.updateCache(name, cache);
		} else {
			// TODO 缓存不存在，添加到缓存,可忽略。
		}
		// TODO 容器存在，写入删除容器任务到临时任务表中
	}

	/**
	 * 更新本节点上的元数据文件
	 * 
	 * @param container
	 */
	@Override
	public void updateMetaContainer(String uuid, MetaContainer meta) {
		MetaProcessor processor = new MetaContainerXMLProcessor();		
		processor.updateMetadata(uuid, meta);
	}

	@Override
	public void setAccessControlPolicy(String container, AccessControlList acl,
			Principal principal) {
		ContainerCache cache = null;
		String uuid = JuuidUtils.getuuid(container);
		cache = (ContainerCache) cache_local.getCache(uuid);
		if (cache != null) {
			if (cache.getStatus() != ContainerStatus.Working.getValue()) {
				// 只有容器状态为正常时，才能进行操作，否则返回409.冲突
				throw new ForbiddenException(ErrorCodes.OperationAborted);
			}
		}

		MetaContainer metafile = this.getMetaContainer(uuid);
		// 从元数据文件，获得容器状态，进行比较
		if (metafile != null) {
			if (metafile.getStatus() != ContainerStatus.Working.getValue()) {
				// 只有容器状态为正常时，才能进行操作，否则返回409.冲突
				throw new ForbiddenException(ErrorCodes.OperationAborted);
			}
		} else {
			// 元数据文件不存在
			throw new NotFoundException(ErrorCodes.NoSuchContainer);
		}

		// 向容器元数据文件中的设置ACL
		metafile.setAccessControlPolicy(acl);
		this.updateMetaContainer(uuid, metafile);

		// 如果存在缓存，则更新缓存状态。
		if (cache != null) {
			cache.setAccessControlPolicy(acl);
			cache_local.updateCache(uuid, cache);
		} else {
			// TODO 缓存不存在，添加到缓存
		}

	}

	/**
	 * 获得容器的ACL属性
	 * 
	 * @param container
	 *            容器名
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	@Override
	public Map<String, String> getAccessControlList(String container,
			Principal principal) {
		Map<String, String> aclMap = null;
		// 优先检查缓存，ACL在第一次ACL认证通过后加入缓存
		String uuid = JuuidUtils.getuuid(container);
		ContainerCache cache = (ContainerCache) cache_local.getCache(uuid);
		if (cache == null || cache.getAccessControlList() == null) {
			MetaContainer metafile = this.getMetaContainer(uuid);
			if (metafile != null) {
				aclMap = metafile.getAccessControlList();
			} else {
				throw new NotFoundException(ErrorCodes.NoSuchContainer);
			}
		} else {
			aclMap = cache.getAccessControlList();
		}
		return aclMap;
	}

	/**
	 * 获得容器的基本属性,
	 * 
	 * @param container
	 *            容器名
	 * @return
	 * @throws NoSuchAlgorithmException
	 */
	@Override
	public ContainerProperties getProperties(String container,
			boolean withMetadata, Principal principal) {
		// 由于容器的元数据信息以及基本属性并不会被缓存起来
		// 所以这里直接读元数据文件
		ContainerProperties properties = null;
		String uuid = JuuidUtils.getuuid(container);
		MetaContainer metafile = this.getMetaContainer(uuid);
		if (metafile != null) {
			properties = new ContainerProperties();
			properties.setCreationDate(metafile.getCreationDate());
			properties.setStatus(metafile.getStatus());
			if (withMetadata) {
				properties.setUserMetadata(metafile.getMetadata());
			}
		} else {
			throw new NotFoundException(ErrorCodes.NoSuchContainer);
		}
		return properties;
	}

	/**
	 * 设置容器的用户元数据信息，元数据暂时不缓存
	 * 
	 * @param container
	 *            容器名
	 * @return
	 */
	@Override
	public void setUserMetadata(String container, Map<String, String> meta,
			Principal principal) {
		String uuid = JuuidUtils.getuuid(container);
		MetaContainer metafile = this.getMetaContainer(uuid);
		if (metafile != null) {
			metafile.setMetadata(meta);
			this.updateMetaContainer(uuid, metafile);
		} else {
			throw new NotFoundException(ErrorCodes.NoSuchContainer);
		}
	}

	@Override
	public Map<String, String> getUserMetadata(String container, Principal principal) {
		Map<String, String> meta = new HashMap<String, String>();
		String uuid = JuuidUtils.getuuid(container);
		MetaContainer metafile = this.getMetaContainer(uuid);
		if (metafile != null) {
			meta = metafile.getMetadata();
		} else {
			throw new NotFoundException(ErrorCodes.NoSuchContainer);
		}
		return meta;
	}

	/************************* 对象操作 ************************/


}
